home *** CD-ROM | disk | FTP | other *** search
- /*•••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
- /* SampleAdditional.c
- /*
- /* This file contains routines to replace the standard ones in Sample.c
- /*
- /* Author: Michael Chen, Human Interface Group / ATG
- /* Copyright © 1991-1993 Apple Computer, Inc. All rights reserved.
- /*
- /* Part of Virtual Sphere Sample Code Release v1.1
- /*•••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••*/
-
- #ifndef __SAMPLEADDITIONAL__
- #include "SampleAdditional.h"
- #endif
-
- #ifndef __TOOLUTILS__
- #include <ToolUtils.h>
- #endif
-
- #ifndef __FIXMATH__
- #include <FixMath.h>
- #endif
-
- #ifndef __ERRORS__
- #include <Errors.h>
- #endif
-
- #ifndef __GRAF3D__
- #include <Graf3D.h>
- #endif
-
- #ifndef __MENUS__
- #include <Menus.h>
- #endif
-
- #ifndef __OFFSCREEN__
- #include "Offscreen.h"
- #endif
-
- #ifndef __MyMath__
- #include "MyMath.h"
- #endif
-
- #ifndef __GRAPHICS3D__
- #include "Graphics3D.h"
- #endif
-
- #ifndef __VIRTUALSPHERE__
- #include "VirtualSphere.h"
- #endif
-
- #include "Sample.h"
-
- #define Long2Fix(x) (Fixed)(x<<16) /* override standard trap call */
- #include "ObjectData.h"
-
- /* Define values for the Virtual Sphere cue circle.
- * In a real application, the cue circle should resize to the currently selected object */
- #define kSphereCenterH 150
- #define kSphereCenterV 150
- #define kSphereRadius 130
-
- /* Routine global to this file (module) only */
- static void DoRotation (WindowPtr window, EventRecord *event, Matrix4D objectMatrix);
-
- /* Variables global to this file (module) only */
- static Port3DPtr lgThePort3DPtr; /* global pointer used to remember the current Port3D */
- static Port3D lgMyPort3D;
- static Matrix4D lgObjectMatrix;
- static GWorldPtr lgOffscreenGWorld = nil;
-
- /*=================================================================================================
- /* Initialize3D
- /*
- /* Set up Graf3D, create an offscreen buffer for the window and display parameters.
- /*-------------------------------------------------------------------------------------------------*/
- void Initialize3D (WindowPtr window)
- {
- Rect globalRect;
- Boolean gWorldAvailable;
-
- /* Setup offscreen buffer */
- if (InitializeOffscreen (&gWorldAvailable) != noErr) {
- MessageAlertAndQuit ("\pInitOffscreen returned an error.");
- }
- if (!gWorldAvailable) {
- MessageAlertAndQuit ("\pThis application requires 32-bit Color Quickdraw or System 7.");
- }
-
- if (CheckOffscreenForWindow (&lgOffscreenGWorld, 0, window) != noErr) {
- /* Note CheckOffscreenForWindow() has already set lgOffscreenGWorld to nil. */
- MessageAlert ("\pThere is not enough memory to do double buffering.");
- gDoubleBuffer = false;
- } else {
- gDoubleBuffer = true;
- }
-
- /* Initialize our 3D graphics rountines */
- if (InitializeGraphics3D() != noErr) {
- MessageAlertAndQuit ("\pInitialzeGraphics3D.");
- }
-
- /* Initialize Graf3D */
- InitGrf3d (&lgThePort3DPtr); /* Must call */
- SetPort (window); /* Make sure OpenPort3D uses the current GrafPort */
- Open3DPort (&lgMyPort3D); /* Open3DPort fills in the lgMyPort3D record with
- * appropriate values (including setting the field
- * lgMyPort3D.grPort to the current GrafPort */
- SetPort3D (&lgMyPort3D); /* Make sure we are using this Port3D */
-
- /* Make the 3D viewport the same size as the window */
- ViewPort (&(lgMyPort3D.grPort->portRect));
-
- /* Set up the 3D viewing pyrimid. Note the top and bottom parameters are flipped so
- * that y increases going up */
- #define kXMin -200
- #define kXMax 200
- #define kYMin -200
- #define kYMax 200
- LookAt (Long2Fix(kXMin), Long2Fix(kYMax), Long2Fix(kXMax), Long2Fix(kYMin));
- ViewAngle (Long2Fix (25));
-
- /* Unset the optimization flag within Graf3D which "remembers" if lgMyPort3D.xForm is
- * identity or not. This is needed since we modify lgMyPort3D.xForm directly via the
- * Matrix2XfMatrix() call below. We never call any of the Graf3D routines which
- * indirectly modify the xForm matrix. */
- Scale (Long2Fix (1), Long2Fix (1), Long2Fix (1)); /* Actually any Graf3D transform call
- * that generates a indentity matrix
- * will do */
-
- /* Initialize the object matrix to identity. Note the object matrix is in floating point.
- * This matrix is then converted and stored into Graf3D's xForm matrix (in Fixed point format). */
- lgObjectMatrix [0][0] = lgObjectMatrix [1][1] = lgObjectMatrix [2][2] = lgObjectMatrix [3][3] = 1;
- lgObjectMatrix [0][1] = lgObjectMatrix [0][2] = lgObjectMatrix [0][3] =
- lgObjectMatrix [1][0] = lgObjectMatrix [1][2] = lgObjectMatrix [1][3] =
- lgObjectMatrix [2][0] = lgObjectMatrix [2][1] = lgObjectMatrix [2][3] =
- lgObjectMatrix [3][0] = lgObjectMatrix [3][1] = lgObjectMatrix [3][2] = 0;
- Matrix2XfMatrix (lgObjectMatrix, lgMyPort3D.xForm);
-
- /* Setup default drawing styles for the 3D object. */
- gObjectDisplayed = iHouse;
- gRenderingStyle = iFlatShading;
- gDoBackfacedPolygonRemoval = true;
- globalRect = window->portRect;
- LocalToGlobalRect (&globalRect);
- gDrawInColor = gMac.hasColorQD && (ScreenDepth (&globalRect) > 1);
- }
-
- /*=================================================================================================
- /* CleanUp3D
- /*
- /* Clean up 3D stuff before quiting application.
- /*-------------------------------------------------------------------------------------------------*/
- void CleanUp3D ()
- {
- FreeOffscreen (lgOffscreenGWorld);
- FreeGraphics3D ();
- }
-
- /*=================================================================================================
- /* AdjustAdditionalMenus
- /*
- /* Enable / disable menus items related to this 3D sample program
- /*-------------------------------------------------------------------------------------------------*/
- void AdjustAdditionalMenus ()
- {
- Boolean isAppWindow;
- MenuHandle menu;
-
- isAppWindow = !IsDAWindow (FrontWindow());
-
- menu = GetMHandle (mObject);
- EnableDisableItem (menu, iCube, isAppWindow);
- EnableDisableItem (menu, iIcosahedron, isAppWindow);
- EnableDisableItem (menu, iHouse, isAppWindow);
- CheckItem (menu, iCube, gObjectDisplayed == iCube);
- CheckItem (menu, iIcosahedron, gObjectDisplayed == iIcosahedron);
- CheckItem (menu, iHouse, gObjectDisplayed == iHouse);
-
- menu = GetMHandle (mOptions);
- EnableDisableItem (menu, iLineDrawing, isAppWindow);
- EnableDisableItem (menu, iFlatShading, isAppWindow);
- EnableDisableItem (menu, iFlatShadingWithOutline, isAppWindow);
- EnableDisableItem (menu, iDrawInBW, isAppWindow);
- EnableDisableItem (menu, iDrawInColor, isAppWindow && gMac.hasColorQD);
- EnableDisableItem (menu, iBackfacedPolygonRemoval, isAppWindow);
- EnableDisableItem (menu, iDoubleBuffer, isAppWindow && (lgOffscreenGWorld != nil));
- CheckItem (menu, iLineDrawing, gRenderingStyle == iLineDrawing);
- CheckItem (menu, iFlatShading, gRenderingStyle == iFlatShading);
- CheckItem (menu, iFlatShadingWithOutline, gRenderingStyle == iFlatShadingWithOutline);
- CheckItem (menu, iDrawInBW, !gDrawInColor);
- CheckItem (menu, iDrawInColor, gDrawInColor);
- CheckItem (menu, iBackfacedPolygonRemoval, gDoBackfacedPolygonRemoval);
- CheckItem (menu, iDoubleBuffer, gDoubleBuffer);
- }
-
- /*=================================================================================================
- /* CheckSystemConfiguration
- /*
- /* If system configuration is not right, alert user and exit to Finder.
- /* Must be universal code
- /*-------------------------------------------------------------------------------------------------*/
- #ifdef applec
- #pragma push /* MPW: save compiler flags */
- #pragma processor 68000 /* Generate 68000 instructions only */
- #endif
- void CheckSystemConfiguration ()
- {
- #ifdef THINK_C /* THINK C: Generate 68020 instructions… */
- #pragma options(!mc68020) /* …NOT! Silly way of saying 68000 */
- #endif /* instructions only. Note this pragma */
- /* is defined only until end of routine. */
-
- if (qUseFPUand020 && !(gMac.hasFPU)) {
- /* Should use string resource to show this message! */
- MessageAlertAndQuit ("\pSorry. You can only run this application on a Mac with a '020 processor and math coprocessor.");
- }
- }
- #ifdef applec
- #pragma pop /* MPW: restore compiler flags */
- #endif
-
- /*=================================================================================================
- /* DoAdditionalMenuCommand
- /*
- /* Deal with menus selections related to this 3D sample program
- /*-------------------------------------------------------------------------------------------------*/
- void DoAdditionalMenuCommand (long menuResult)
- {
- short menuID; /* the resource ID of the selected menu */
- short menuItem; /* the item number of the selected menu */
- WindowPtr window;
-
- menuID = HiWord (menuResult); /* use macros for efficiency to... */
- menuItem = LoWord (menuResult); /* get menu item number and menu number */
- window = FrontWindow ();
-
- switch (menuID) {
- case mObject:
- switch (menuItem) {
- case iCube:
- gObjectDisplayed = iCube;
- break;
- case iIcosahedron:
- gObjectDisplayed = iIcosahedron;
- break;
- case iHouse:
- gObjectDisplayed = iHouse;
- break;
- }
- InvalRect (&window->portRect);
- break;
- case mOptions:
- switch (menuItem) {
- case iLineDrawing:
- gRenderingStyle = iLineDrawing;
- break;
- case iFlatShading:
- gRenderingStyle = iFlatShading;
- break;
- case iFlatShadingWithOutline:
- gRenderingStyle = iFlatShadingWithOutline;
- break;
- case iBackfacedPolygonRemoval:
- gDoBackfacedPolygonRemoval = !gDoBackfacedPolygonRemoval;
- break;
- case iDoubleBuffer:
- gDoubleBuffer = !gDoubleBuffer;
- break;
- case iDrawInBW:
- gDrawInColor = false;
- break;
- case iDrawInColor:
- gDrawInColor = true;
- break;
- }
- InvalRect (&window->portRect);
- break;
- }
- }
-
- /*=================================================================================================
- /* DoContentClick
- /*
- /* Called when there is a mouse down in the window content.
- /* In this sample app, we only need to rotate the displayed object. In a more
- /* complex app, you would probably need to determine which object is clicked and
- /* figure out what operation you should apply to that object.
- /*-------------------------------------------------------------------------------------------------*/
- void DoContentClick (WindowPtr window, EventRecord *event)
- {
- DoRotation (window, event, lgObjectMatrix);
- }
-
- /*=================================================================================================
- /* DoRotation
- /*
- /* Called when there is a mouse down in the window content.
- /* Use the Virtual Sphere to rotate the current object on the screen.
- /* In a 3D graphics program, an objects usually has associated with it a "modeling" matrix.
- /* An object is rotated by modifying its modeling matrix. This is done here by repeatedly
- /* concatenating the rotation determined by the Virtual Sphere to the object's matrix while
- /* the user is dragging the mouse.
- /*-------------------------------------------------------------------------------------------------*/
- static void DoRotation (WindowPtr window, EventRecord *event, Matrix4D objectMatrix)
- {
- Point p, q;
- short dx, dy;
- Point sphereCenter;
- Integer sphereRadius;
- Matrix4D tempMatrix;
- Matrix4D rotationMatrix;
-
- SetCursor (*GetCursor(crossCursor));
-
- p = event->where;
- GlobalToLocal (&p); /* Get the mouse down point in local coordinates. */
-
- /* Figure out where to place the Virtual Sphere cue.
- * In this sample app., the cue is always centered on the window with a fixed size.
- * In an general app., you will need to determine the location and size of cue
- * (in screen coordinates) to surround the object */
- sphereCenter.h = kSphereCenterH;
- sphereCenter.v = kSphereCenterV;
- sphereRadius = kSphereRadius;
-
- while (StillDown()) {
- GetMouse (&q);
- dx = q.h - p.h;
- dy = q.v - p.v;
- if (dx != 0 || dy != 0) {
- /* Determine the rotation matrix from the mouse movement */
- VirtualSphere (p, q, sphereCenter, sphereRadius, rotationMatrix);
-
- /* Concatenate the new rotation with the current rotation */
- MultiplyMatrix (objectMatrix, rotationMatrix, tempMatrix);
- CopyMatrix (tempMatrix, objectMatrix);
-
- /* The next routine may be called if the objectMatrix really gets "out of shape"
- * due to numeric inaccuracies from repeated matrix multiplications. This does not
- * happen in this demo program so the call is commented out */
- /* OrthogonalizeRotationMatrix (objectMatrix); */
-
- /* Update the window */
- DrawWindow (window);
-
- p = q; /* Remember previous mouse point for next iteration. */
- }
- }
- }
-
- /*=================================================================================================
- /* DrawWindow
- /*
- /* Draw the current 3D object and surround it with the Virtual Sphere cue. In this sample
- /* application, the object is always centered on the window with a fixed size.
- /* In an general app., you will need to determine the location and size of sphere
- /* to surround the object.
- /*-------------------------------------------------------------------------------------------------*/
- void DrawWindow (WindowPtr window)
- {
- Rect sphereRect;
-
- SetPort3D (&lgMyPort3D);
- /* Convert and store our matrix into the Graf3D matrix */
- Matrix2XfMatrix (lgObjectMatrix, lgMyPort3D.xForm);
-
- if (gDoubleBuffer) BeginDrawingOffscreen (lgOffscreenGWorld, window);
-
- EraseRect (&qd.thePort->portRect);
-
- /* Draw the object */
- switch (gObjectDisplayed) {
- case iCube:
- DrawPolyNet (&gCubeData);
- break;
- case iIcosahedron:
- DrawPolyNet (&gIcosahedronData);
- break;
- case iHouse:
- DrawPolyNet (&gHouseData);
- break;
- }
-
- /* Draw Virtual Sphere cue around the object */
- SetRect (&sphereRect, kSphereCenterH-kSphereRadius, kSphereCenterV-kSphereRadius,
- kSphereCenterH+kSphereRadius, kSphereCenterV+kSphereRadius);
- ForeColor (magentaColor);
- FrameOval (&sphereRect);
-
- if (gDoubleBuffer) EndDrawingOffscreen (lgOffscreenGWorld, window);
- }
-
- /*=================================================================================================
- /* UpdateWindow
- /*
- /* Deal with update event. Reallocate the offscreen buffer if the window has been moved
- /* or the bit-depth has been changed. Then draw the window content if needed.
- /*-------------------------------------------------------------------------------------------------*/
- void UpdateWindow (WindowPtr window)
- {
- if (gDoubleBuffer) {
- if (CheckOffscreenForWindow (&lgOffscreenGWorld, 0, window) == memFullErr) {
- MessageAlert ("\pThere is not enough memory to do double buffering for this screen depth.");
- if (lgOffscreenGWorld == nil) gDoubleBuffer = false;
- }
- }
-
- BeginUpdate (window);
-
- if (!EmptyRgn (window->visRgn)) {
- /* Updating needs to be done */
- DrawWindow (window);
- }
-
- EndUpdate (window);
- }
-